//! Nacos配置管理客户端

use crate::client::NacosClient;
use crate::error::ClientError;
use crate::ClientResult;
use nacos_core::ConfigItem;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::NacosClientApi;

/// 配置监听回调
pub type ConfigChangeListener = Arc<dyn Fn(ConfigItem) + Send + Sync>;

/// 配置客户端
pub struct ConfigClient {
    client: Arc<dyn NacosClientApi>,
    listeners: Arc<RwLock<HashMap<String, Vec<ConfigChangeListener>>>>,
}

impl ConfigClient {
    /// 创建新的配置客户端
    pub fn new(client: Arc<dyn NacosClientApi>) -> Self {
        Self {
            client,
            listeners: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// 获取配置
    pub async fn get_config(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
    ) -> ClientResult<ConfigItem> {
        let url = format!(
            "{}/nacos/v1/cs/configs?dataId={}&group={}&namespaceId={}",
            self.client.config().server_url(),
            data_id,
            group,
            namespace
        );

        let response = self.client.http_client()
            .get(&url, &[])
            .await?;

        if response.status().is_success() {
            let content = response.text().await
                .map_err(|e| ClientError::NetworkError(e.to_string()))?;
            
            let config_item = ConfigItem::new(
                data_id.to_string(),
                group.to_string(),
                content,
            );
            
            Ok(config_item)
        } else {
            Err(ClientError::ConfigError(format!(
                "Failed to get config: {}",
                response.status()
            )))
        }
    }

    /// 发布配置
    pub async fn publish_config(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
        content: &str,
    ) -> ClientResult<bool> {
        let url = format!("{}/nacos/v1/cs/configs", self.client.config().server_url());

        let params = vec![
            ("dataId".to_string(), data_id.to_string()),
            ("group".to_string(), group.to_string()),
            ("namespaceId".to_string(), namespace.to_string()),
            ("content".to_string(), content.to_string()),
        ];

        let response = self.client.http_client()
            .post(&url, &params)
            .await?;

        if response.status().is_success() {
            let result = response.text().await
                .map_err(|e| ClientError::NetworkError(e.to_string()))?;
            Ok(result == "true")
        } else {
            Err(ClientError::ConfigError(format!(
                "Failed to publish config: {}",
                response.status()
            )))
        }
    }

    /// 删除配置
    pub async fn delete_config(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
    ) -> ClientResult<bool> {
        let url = format!("{}/nacos/v1/cs/configs", self.client.config().server_url());

        let params = vec![
            ("dataId".to_string(), data_id.to_string()),
            ("group".to_string(), group.to_string()),
            ("namespaceId".to_string(), namespace.to_string()),
        ];

        let response = self.client.http_client()
            .delete(&url, &params)
            .await?;

        if response.status().is_success() {
            let result = response.text().await
                .map_err(|e| ClientError::NetworkError(e.to_string()))?;
            Ok(result == "true")
        } else {
            Err(ClientError::ConfigError(format!(
                "Failed to delete config: {}",
                response.status()
            )))
        }
    }

    /// 监听配置变更
    pub async fn add_listener(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
        listener: ConfigChangeListener,
    ) -> ClientResult<()> {
        let key = format!("{}:{}:{}", namespace, group, data_id);
        
        let mut listeners = self.listeners.write().await;
        listeners.entry(key).or_insert_with(Vec::new).push(listener);
        
        Ok(())
    }

    /// 移除监听器
    pub async fn remove_listener(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
    ) -> ClientResult<()> {
        let key = format!("{}:{}:{}", namespace, group, data_id);
        
        let mut listeners = self.listeners.write().await;
        listeners.remove(&key);
        
        Ok(())
    }

    /// 检查配置是否存在
    pub async fn check_config(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
    ) -> ClientResult<bool> {
        let url = format!(
            "{}/nacos/v1/cs/configs?dataId={}&group={}&namespaceId={}",
            self.client.config().server_url(),
            data_id,
            group,
            namespace
        );

        let response = self.client.http_client()
            .get(&url, &[])
            .await?;

        Ok(response.status().is_success())
    }

    /// 获取配置历史版本
    pub async fn get_config_history(
        &self,
        data_id: &str,
        group: &str,
        namespace: &str,
        page_no: i32,
        page_size: i32,
    ) -> ClientResult<Vec<ConfigHistoryItem>> {
        let url = format!(
            "{}/nacos/v1/cs/history/configs?dataId={}&group={}&namespaceId={}&pageNo={}&pageSize={}",
            self.client.config().server_url(),
            data_id,
            group,
            namespace,
            page_no,
            page_size
        );

        let response = self.client.http_client()
            .get(&url, &[])
            .await?;

        if response.status().is_success() {
            let history: Vec<ConfigHistoryItem> = response.json().await
                .map_err(|e| ClientError::SerializationError(e.to_string()))?;
            Ok(history)
        } else {
            Err(ClientError::ConfigError(format!(
                "Failed to get config history: {}",
                response.status()
            )))
        }
    }

    /// 获取监听器的配置客户端
    pub(crate) fn listeners(&self) -> Arc<RwLock<HashMap<String, Vec<ConfigChangeListener>>>> {
        self.listeners.clone()
    }
}

/// 配置历史记录项
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigHistoryItem {
    pub id: i64,
    pub data_id: String,
    pub group: String,
    pub namespace_id: String,
    pub content: String,
    pub md5: String,
    pub src_user: Option<String>,
    pub src_ip: Option<String>,
    pub op_type: String,
    pub created_time: i64,
    pub last_modified_time: i64,
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;

    #[tokio::test]
    async fn test_config_client_creation() {
        // 这个测试需要实际的Nacos服务器，所以只是编译测试
        let _client = ConfigClient::new(Arc::new(crate::client::MockNacosClient::new()) as Arc<dyn crate::client::NacosClientApi>);
    }

    #[test]
    fn test_config_history_item() {
        let history = ConfigHistoryItem {
            id: 1,
            data_id: "test-data-id".to_string(),
            group: "test-group".to_string(),
            namespace_id: "public".to_string(),
            content: "test content".to_string(),
            md5: "d41d8cd98f00b204e9800998ecf8427e".to_string(),
            src_user: Some("user".to_string()),
            src_ip: Some("127.0.0.1".to_string()),
            op_type: "I".to_string(),
            created_time: 1234567890,
            last_modified_time: 1234567890,
        };

        assert_eq!(history.data_id, "test-data-id");
        assert_eq!(history.group, "test-group");
    }
}